"""
设置界面模块 - 提供统一的配置界面
"""

import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import json
import os
from typing import Dict, Callable, List
from configs_all import configs_data  # 更新为新的目录结构
import sys
from datetime import datetime
from configs.output_markdowns import MarkdownExporter


def open_data_folder():
    """Open data folder in file explorer"""
    try:
        import platform, subprocess
        data_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data")
        if platform.system() == 'Windows':
            os.startfile(data_dir)
        elif platform.system() == 'Darwin':  # macOS
            subprocess.run(['open', data_dir])
        else:  # linux
            subprocess.run(['xdg-open', data_dir])
    except Exception as e:
        from loguru import logger
        logger.error(f"Failed to open data folder: {str(e)}")


class SettingsWindow:
    # 添加类变量跟踪窗口实例
    _instance = None
    
    def __new__(cls, parent, callback: Callable = None):
        if cls._instance is not None and cls._instance.window.winfo_exists():
            cls._instance.window.focus_force()  # 将已存在的窗口置于前台
            cls._instance.window.lift()  # 确保窗口在最上层
            return None
        return super().__new__(cls)
    
    def __init__(self, parent, callback: Callable = None):
        # 如果是重复创建实例，直接返回
        if hasattr(self, 'window'):
            return
            
        self.window = tk.Toplevel(parent)
        self.window.title("其他设置")
        self.window.geometry("600x400")
        
        # 保存实例引用
        self.__class__._instance = self
        
        # 绑定窗口关闭事件
        self.window.protocol("WM_DELETE_WINDOW", self._on_closing)
        
        self.callback = callback
        
        # 加载当前配置
        self.current_config = self.load_current_config()
        
        # 加载路径历史记录
        self.path_history = self.current_config.get('path_history', ['data'])
        if not isinstance(self.path_history, list):
            self.path_history = ['data']
            
        # 确保data目录始终在第一位
        if 'data' in self.path_history:
            self.path_history.remove('data')
        self.path_history.insert(0, 'data')
        
        # 检查当前使用的路径是否在历史记录中
        current_path = self.current_config.get('data_dir', 'data')
        if current_path not in self.path_history:
            self.path_history.insert(1, current_path)  # 插入到data目录之后
            
        # 保持最多10条记录
        self.path_history = self.path_history[:10]
        
        self.setup_ui()
        
        # 绑定右键双击关闭窗口
        self.window.bind('<Double-Button-3>', lambda e: self.window.destroy())
        
    def _on_closing(self):
        """窗口关闭时的处理"""
        self.__class__._instance = None  # 清除实例引用
        self.window.destroy()
        
    def setup_ui(self):
        """设置UI界面"""
        # 创建主Canvas用于滚动
        self.canvas = tk.Canvas(self.window)
        scrollbar = ttk.Scrollbar(self.window, orient="vertical", command=self.canvas.yview)
        
        # 创建主框架
        self.main_frame = ttk.Frame(self.canvas)
        
        # 配置Canvas滚动
        self.main_frame.bind(
            "<Configure>",
            lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
        )
        self.canvas.create_window((0, 0), window=self.main_frame, anchor="nw")
        self.canvas.configure(yscrollcommand=scrollbar.set)
        
        # 绑定鼠标滚轮
        def _on_mousewheel(event):
            self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")
        self.canvas.bind_all("<MouseWheel>", _on_mousewheel)
        
        # 布局Canvas和滚动条
        self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 添加打开data目录的按钮 - 放在最上面
        self.open_data_btn = ttk.Button(
            self.main_frame,
            text="打开提示词目录",
            command=self.open_prompt_folder,
            width=20  # 设置按钮宽度
        )
        self.open_data_btn.pack(pady=10)
        
        # 添加导出markdown的按钮
        self.export_md_btn = ttk.Button(
            self.main_frame,
            text="所有提示词导出为markdown文件",
            command=export_prompts_to_markdown,
            width=30
        )
        self.export_md_btn.pack(pady=5)  # 减小与下一个按钮的间距
        
        # 添加打开markdown导出目录的按钮
        self.open_export_dir_btn = ttk.Button(
            self.main_frame,
            text="打开导出的markdown文件目录",
            command=open_markdown_export_folder,
            width=30
        )
        self.open_export_dir_btn.pack(pady=10)
        
        # 创建数据路径配置区域
        self.create_data_path_section()
        
        # 创建文件列表配置区域
        self.create_file_list_section()
        
        # 创建按钮区域
        self.create_button_area()
        
    def create_data_path_section(self):
        """创建数据路径配置区域"""
        # 添加说明标签
        ttk.Label(
            self.main_frame,
            text="数据路径配置",
            font=('Arial', 12, 'bold')
        ).pack(pady=10)
        
        # 创建配置框架
        path_frame = ttk.LabelFrame(self.main_frame, text="路径设置", padding=10)
        path_frame.pack(fill=tk.X, padx=10, pady=5)
        
        # 数据目录选择
        data_dir_frame = ttk.Frame(path_frame)
        data_dir_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(data_dir_frame, text="数据目录:").pack(side=tk.LEFT)
        
        # 创建路径历史下拉菜单
        self.path_var = tk.StringVar(value=self.current_config.get('data_dir', 'data'))
        self.path_combobox = ttk.Combobox(
            data_dir_frame,
            textvariable=self.path_var,
            values=self.path_history,
            state='readonly' if self.path_history else 'normal'
        )
        self.path_combobox.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
        
        # 绑定下拉菜单选择事件
        self.path_combobox.bind('<<ComboboxSelected>>', self.on_path_selected)
        
        ttk.Button(
            data_dir_frame,
            text="浏览",
            command=self.browse_directory
        ).pack(side=tk.LEFT)
        
        # 子目录包含选项
        self.include_subdirs_var = tk.BooleanVar(
            value=self.current_config.get('include_subdirs', True)
        )
        ttk.Checkbutton(
            path_frame,
            text="包含子目录",
            variable=self.include_subdirs_var
        ).pack(anchor='w', pady=5)
        
        # 文件扩展名
        ext_frame = ttk.Frame(path_frame)
        ext_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(ext_frame, text="文件扩展名:").pack(side=tk.LEFT)
        self.file_ext_entry = ttk.Entry(ext_frame)
        self.file_ext_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
        self.file_ext_entry.insert(0, self.current_config.get('file_extension', '.json'))
        
        # 添加打开data目录的按钮
        self.open_data_btn = ttk.Button(
            path_frame,
            text="打开提示词数据文件目录",
            command=self.open_prompt_folder
        )
        self.open_data_btn.pack(pady=5)
        
    def create_file_list_section(self):
        """创建文件列表配置区域"""
        # 添加说明标签
        ttk.Label(
            self.main_frame,
            text="文件列表置",
            font=('Arial', 12, 'bold')
        ).pack(pady=10)
        
        # 创建配置框架
        list_frame = ttk.LabelFrame(self.main_frame, text="列表设置", padding=10)
        list_frame.pack(fill=tk.X, padx=10, pady=5)
        
        # 字体大小设置
        font_frame = ttk.Frame(list_frame)
        font_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(font_frame, text="字体大小:").pack(side=tk.LEFT)
        self.font_size_var = tk.StringVar(value=str(self.current_config.get('file_list_font_size', 15)))
        font_size_spinbox = ttk.Spinbox(
            font_frame,
            from_=8,
            to=36,
            width=5,
            textvariable=self.font_size_var
        )
        font_size_spinbox.pack(side=tk.LEFT, padx=5)
        
        # 列表宽度设置
        width_frame = ttk.Frame(list_frame)
        width_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(width_frame, text="列表宽度:").pack(side=tk.LEFT)
        self.width_var = tk.StringVar(value=str(self.current_config.get('file_list_width', 19)))
        width_spinbox = ttk.Spinbox(
            width_frame,
            from_=10,
            to=50,
            width=5,
            textvariable=self.width_var
        )
        width_spinbox.pack(side=tk.LEFT, padx=5)
        ttk.Label(width_frame, text="字符数").pack(side=tk.LEFT)
        
    def create_button_area(self):
        """创建按钮区域"""
        button_frame = ttk.Frame(self.window)
        button_frame.pack(side=tk.BOTTOM, fill=tk.X, padx=10, pady=10)
        
        # 应用按钮 - 使用高亮颜色
        self.apply_button = tk.Button(
            button_frame,
            text="应用更改",
            command=self.apply_changes,
            bg='light green',
            activebackground='green'
        )
        self.apply_button.pack(side=tk.LEFT, padx=5)
        
        # 取消按钮
        ttk.Button(
            button_frame,
            text="取消",
            command=self.window.destroy
        ).pack(side=tk.RIGHT, padx=5)
        
    def on_path_selected(self, event):
        """处理路径下拉菜单选择事件"""
        selected_path = self.path_var.get()
        if selected_path and os.path.exists(selected_path):
            self.path_combobox.set(selected_path)

    def update_path_history(self, new_path: str):
        """更新路径历史记录"""
        if not new_path:
            return
            
        # 确保data目录始终在第一位
        if new_path != 'data':
            # 如果新路径已存在，先移除
            if new_path in self.path_history:
                self.path_history.remove(new_path)
            # 将新路径添加到data目录之后
            self.path_history.insert(1, new_path)
            
        # 保持最多10条记录
        self.path_history = self.path_history[:10]
        
        # 更新下拉菜单的值
        self.path_combobox['values'] = self.path_history
        
    def browse_directory(self):
        """浏览选择目录"""
        directory = filedialog.askdirectory(
            initialdir=self.path_var.get()
        )
        if directory:
            self.path_var.set(directory)
            self.update_path_history(directory)
            # 将焦点重新设置到设置窗口
            self.window.focus_force()
            # 确保窗口显示在最前面
            self.window.lift()

    def load_current_config(self) -> Dict:
        """加载当前配置"""
        try:
            if os.path.exists(configs_data.CONFIG_FILE):
                with open(configs_data.CONFIG_FILE, 'r', encoding='utf-8') as f:
                    return json.load(f)
        except Exception as e:
            print(f"加载配置文件失败: {str(e)}")
        return configs_data.DATA_PATHS
        
    def apply_changes(self):
        """应用更改"""
        try:
            # 获取新的配置
            new_config = {
                'data_dir': self.path_var.get().strip(),
                'include_subdirs': self.include_subdirs_var.get(),
                'file_extension': self.file_ext_entry.get().strip(),
                'file_list_font_size': int(self.font_size_var.get()),
                'file_list_width': int(self.width_var.get()),
                'path_history': self.path_history  # 保存路径历史记录
            }
            
            # 验证配置
            if not new_config['data_dir']:
                raise ValueError("数据目录不能为空")
            if not new_config['file_extension']:
                raise ValueError("文件扩展名不能为空")
            if not (8 <= new_config['file_list_font_size'] <= 36):
                raise ValueError("字体大小必须在8-36之间")
            if not (10 <= new_config['file_list_width'] <= 50):
                raise ValueError("列表宽度必须在10-50之间")
                
            # 确保目录存在
            os.makedirs(new_config['data_dir'], exist_ok=True)
            
            # 更新路径历史
            self.update_path_history(new_config['data_dir'])
            
            # 保存配置
            os.makedirs(os.path.dirname(configs_data.CONFIG_FILE), exist_ok=True)
            with open(configs_data.CONFIG_FILE, 'w', encoding='utf-8') as f:
                json.dump(new_config, f, indent=4, ensure_ascii=False)
                
            # 调用回调函数
            if self.callback:
                self.callback(new_config)
                
            messagebox.showinfo(
                "成功",
                "配置已保存，正在重新加载数据...",
                parent=self.window
            )
            self.window.destroy()
            
        except Exception as e:
            messagebox.showerror(
                "错误",
                f"保存配置失败: {str(e)}",
                parent=self.window
            )

    def open_prompt_folder(self):
        """Open configured prompt folder in file explorer"""
        try:
            import platform, subprocess
            # 使用当前配置的目录
            prompt_dir = self.path_var.get().strip()
            if not prompt_dir:
                prompt_dir = self.current_config.get('data_dir', 'data')
            
            # 检查目录是否存在
            if not os.path.exists(prompt_dir):
                messagebox.showerror(
                    "错误",
                    f"提示词目录不存在: {prompt_dir}",
                    parent=self.window
                )
                return
            
            if platform.system() == 'Windows':
                os.startfile(prompt_dir)
            elif platform.system() == 'Darwin':  # macOS
                subprocess.run(['open', prompt_dir])
            else:  # linux
                subprocess.run(['xdg-open', prompt_dir])
        except Exception as e:
            from loguru import logger
            logger.error(f"Failed to open prompt folder: {str(e)}")
            messagebox.showerror(
                "错误",
                f"打开目录失败: {str(e)}",
                parent=self.window
            )


def export_prompts_to_markdown():
    """导出所有提示词到Markdown文件"""
    config = get_config()
    data_dir = config.get('data_dir', 'data')
    output_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "markdown_exports")
    exporter = MarkdownExporter(data_dir, output_dir)
    stats = exporter.export_all_prompts_to_markdown()
    # 替换原有的messagebox.showinfo部分
    result_message = (
        f"总文件数: {stats['total']}\n"
        f"成功: {stats['success']}\n"
        f"失败: {len(stats['failed'])}\n"
        f"跳过: {len(stats['skipped'])}\n\n"
        f"（使用鼠标滚轮滚动查看）"
    )
    
    # 创建自定义滚动对话框
    dialog = tk.Toplevel()
    dialog.title("导出完成")
    dialog.geometry("400x300")
    
    # 添加滚动文本框
    text_frame = tk.Frame(dialog)
    scrollbar = tk.Scrollbar(text_frame)
    text = tk.Text(
        text_frame, 
        wrap=tk.WORD,
        yscrollcommand=scrollbar.set,
        padx=10,
        pady=10
    )
    text.insert(tk.END, result_message)
    text.config(state=tk.DISABLED)
    
    # 配置滚动条
    scrollbar.config(command=text.yview)
    scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
    text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
    text_frame.pack(fill=tk.BOTH, expand=True)
    
    # 添加确定按钮
    btn_frame = tk.Frame(dialog)
    tk.Button(
        btn_frame,
        text="确定",
        command=dialog.destroy
    ).pack(pady=10)
    btn_frame.pack(fill=tk.X)
    
    # 绑定鼠标滚轮事件
    def _on_mousewheel(event):
        text.yview_scroll(int(-1*(event.delta/120)), "units")
    text.bind("<MouseWheel>", _on_mousewheel)
    
    # 设置父窗口
    if SettingsWindow._instance:
        dialog.transient(SettingsWindow._instance.window)
    for file, result in stats['failed']:
        messagebox.showwarning(
            "导出失败",
            f"文件: {file}\n原因: {result}",
            parent=SettingsWindow._instance.window if SettingsWindow._instance else None
        )


def open_markdown_export_folder():
    """打开导出的markdown文件目录"""
    config = get_config()
    output_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "markdown_exports")
    exporter = MarkdownExporter(config.get('data_dir', 'data'), output_dir)
    exporter.open_export_directory()


def get_config() -> Dict:
    """获当前配置"""
    try:
        if os.path.exists(configs_data.CONFIG_FILE):
            with open(configs_data.CONFIG_FILE, 'r', encoding='utf-8') as f:
                return json.load(f)
    except Exception as e:
        print(f"读取配置文件失败: {str(e)}")
    return configs_data.DATA_PATHS 

def verify_prompt_dir() -> bool:
    """验证提示词目录是否有效,无效则提示设置默认路径
    返回: True 表示使用有效目录, False 表示目录无效但用户选择继续
    """
    config = get_config()
    prompt_dir = config.get('data_dir', 'data')
    
    # 如果是相对路径,转换为相对于程序根目录的绝对路径
    if not os.path.isabs(prompt_dir):
        root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        prompt_dir = os.path.join(root_dir, prompt_dir)
    
    if not os.path.exists(prompt_dir):
        # 提示用户是否使用默认data目录
        root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        default_dir = os.path.join(root_dir, 'data')
        
        answer = messagebox.askyesno(
            "提示词目录无效",
            f"当前提示词目录 '{prompt_dir}' 不存在。\n是否使用默认目录 '{default_dir}'?",
            icon='warning'
        )
        
        if answer:
            try:
                # 只在默认data目录不存在时才创建
                if not os.path.exists(default_dir):
                    os.makedirs(default_dir)
                
                # 更新配置文件
                new_config = config.copy()
                new_config['data_dir'] = 'data'  # 使用相对路径
                
                os.makedirs(os.path.dirname(configs_data.CONFIG_FILE), exist_ok=True)
                with open(configs_data.CONFIG_FILE, 'w', encoding='utf-8') as f:
                    json.dump(new_config, f, indent=4, ensure_ascii=False)
                return True
            except Exception as e:
                messagebox.showerror("错误", f"创建默认目录失败: {str(e)}")
                return False
        
        # 用户选择取消,显示提示
        messagebox.showinfo(
            "提示",
            "将以空数据启动程序。您可以稍后在设置中配置提示词目录。"
        )
    return True 